package com.ling.sdk.utils

import java.util.concurrent.*

class WorkThreadFactory : ThreadFactory, Thread.UncaughtExceptionHandler {

    private var thread: Thread? = null
    private var runnables: LinkedBlockingQueue<Runnable>? = null
    private var executor: ExecutorService? = null
    private var stop: Stop? = null
    private var myUncaughtExceptionHandler: MyUncaughtExceptionHandler? = null
    private var threadName = "WorkTread"

    override fun newThread(r: Runnable): Thread {
        return Thread(r).also {
            thread = it
            it.isDaemon = true
            it.name = threadName
            stop = Stop()
            if (myUncaughtExceptionHandler == null)
                myUncaughtExceptionHandler = MyUncaughtExceptionHandler(stop, runnables, this)
            it.uncaughtExceptionHandler = myUncaughtExceptionHandler

        }
    }

    override fun uncaughtException(t: Thread, e: Throwable) {
        if (stop == null || !stop!!.isStop)
            createThreadPool(1, 1, 0L, this, runnables)
    }


    companion object {

        fun createThreadPool(token: String?, size: Int): WorkThreadFactory {
            val workThreadFactory = WorkThreadFactory()
            if (token != null) workThreadFactory.threadName = token
            workThreadFactory.runnables = LinkedBlockingQueue()
            return createThreadPool(size, size, 0L, workThreadFactory, workThreadFactory.runnables)
        }

        fun createThreadPool(corePoolSize: Int, maximumPoolSize: Int, keepAliveTime: Long, workThreadFactory: WorkThreadFactory, runnables: LinkedBlockingQueue<Runnable>?): WorkThreadFactory {
            workThreadFactory.executor = ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.NANOSECONDS, runnables, workThreadFactory)
            return workThreadFactory
        }
    }


    fun shutdownNow() {
        if (stop == null)
            stop = Stop()
        stop?.isStop = true
        if (executor != null)
            executor!!.shutdownNow()
        clearUncaughtExceptionHandler()
        if (thread != null)
            thread!!.uncaughtExceptionHandler = null
        runnables!!.clear()
    }


    fun execute(command: Runnable?) {
        if (command == null)
            return

        if (executor != null)
            executor!!.execute(command)
    }


    class Stop {

        var isStop = false
    }

    private fun clearUncaughtExceptionHandler() {
        myUncaughtExceptionHandler?.also {
            it.runnables = null
            it.factory = null
            it.stop = null
        }
    }


    internal class MyUncaughtExceptionHandler(var stop: Stop?, var runnables: LinkedBlockingQueue<Runnable>?, var factory: WorkThreadFactory?) : Thread.UncaughtExceptionHandler {

        override fun uncaughtException(t: Thread, e: Throwable) {
            if (stop?.isStop != true)
                if (factory != null && runnables != null)
                    createThreadPool(1, 1, 0L, factory!!, runnables)
        }
    }

}